package com.umgsai.wx.backend.test;

import cn.hutool.core.util.IdUtil;
import com.umgsai.wx.backend.BaseTest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.util.Random;

import static com.umgsai.wx.backend.test.OpenCVTest.imageToBinaryString;

@Slf4j
public class OpenCVTest1 extends BaseTest {

    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    private static final int IMAGE_SIZE = 500;
    private static final int DOT_RADIUS = 5; // 圆点半径
    private static final double NOISE_DENSITY = 0; // 噪声密度
    private static final int SPACING = 5; // 点之间的间隔

    @Test
    public void test() throws Exception {
//        int number = 123456789; // 转换的数字
//        String binaryString = Integer.toBinaryString(number); // 数字的二进制表示
//        String serialCode = IdUtil.fastSimpleUUID();
        String serialCode = "d6af29fec6b643dcb04ce70d1a7ce939";
        log.info("serialCode:{}", serialCode);
        String binaryString = convertStringToBinary(serialCode);

        // 添加开始和结束的定位码
        String startMarker = "00000";
        String endMarker = "111111100";
        String markedBinaryString = startMarker + binaryString + endMarker;

        log.info(markedBinaryString);

        // 创建带有随机噪声的图像
        Mat noisyImage = createNoisyImage(240, 480);

        // 在图像中插入编码后的数据
        insertEncodedDataIntoImage(noisyImage, markedBinaryString);

        // 写入图片到文件
        Imgcodecs.imwrite("D:\\binary_image_multiline_dots.png", noisyImage);

        // 读取图片文件
        Mat readImage = Imgcodecs.imread("D:\\binary_image_multiline_dots.png", Imgcodecs.IMREAD_GRAYSCALE);
        // 将图片转换回二进制字符串
        String decodedBinaryString = imageToBinaryString(readImage);
        // 将二进制字符串转换回数字
        String decodedNumber = convertStringToBinary(decodedBinaryString);
        log.info(decodedNumber);
        log.info("result:{}", decodedNumber.equals(binaryString));
    }

    // ... createNoisyImage remains unchanged ...

    private static void insertEncodedDataIntoImage(Mat image, String binaryString) {
        log.info("string length:{}", binaryString.length());
        // 分三行显示数据
        int lineLength = (binaryString.length() / 10) + (binaryString.length() % 10 > 0 ? 1 : 0);
        log.info("lineLength length:{}", lineLength);
        // 计算每行的起始y坐标
        int firstLineY = IMAGE_SIZE / 2 - SPACING - DOT_RADIUS * 2;
        int secondLineY = IMAGE_SIZE / 2;
        int thirdLineY = IMAGE_SIZE / 2 + SPACING + DOT_RADIUS * 2;

        String[] strings = stringToStringArray(binaryString, lineLength);
        for (int i = 0; i < strings.length; i++) {
            int lineY = SPACING + (i + 1) * DOT_RADIUS * 4;
            log.info("{} lineY:{}", strings[i], lineY);
            drawDataLine(image, strings[i], lineY);
        }

        // 绘制每一行的数据
        /*
        for (int i = 0; i < 10; i++) {
            int beginIndex = i * lineLength;
            int endIndex = (i + 1) * lineLength;
            if (i >= 9) {
                endIndex = binaryString.length() - 1;
            }
            int lineY = SPACING + (i + 1) * DOT_RADIUS * 4;
            log.info("beginIndex:{} endIndex:{} lineY:{}", beginIndex, endIndex, lineY);
            drawDataLine(image, binaryString.substring(beginIndex, endIndex), lineY);
        }
        */
        /*
        drawDataLine(image, binaryString.substring(0, lineLength), firstLineY);
        drawDataLine(image, binaryString.substring(lineLength, 2 * lineLength), secondLineY);
        drawDataLine(image, binaryString.substring(2 * lineLength), thirdLineY);
        */
    }

    private static void drawDataLine(Mat image, String data, int centerY) {
        int startX = (IMAGE_SIZE - (data.length() * (DOT_RADIUS * 2 + SPACING))) / 2;

        for (int i = 0; i < data.length(); i++) {
            int value = data.charAt(i) == '1' ? 255 : 127;
            Point center = new Point(startX + i * (DOT_RADIUS * 2 + SPACING), centerY);
            Imgproc.circle(image, center, DOT_RADIUS, new Scalar(value), -1);
        }
    }

    private static Mat createNoisyImage(int width, int height) {
        Mat mat = new Mat(width, height, CvType.CV_8UC1, new Scalar(127)); // 初始灰色背景
        Random rand = new Random();

        // 每个像素点有40%的概率是噪声
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                if (rand.nextDouble() < NOISE_DENSITY) {
                    int value = rand.nextBoolean() ? 255 : 0;
                    mat.put(i, j, value);
                }
            }
        }

        return mat;
    }

    public static String convertStringToBinary(String input) {
        StringBuilder result = new StringBuilder();
        char[] chars = input.toCharArray();
        for (char aChar : chars) {
            result.append(
                    String.format("%8s", Integer.toBinaryString(aChar))   // char -> int, auto-cast
                            .replaceAll(" ", "0")                         // zero pads
            );
        }
        return result.toString();
    }

    private static String[] stringToStringArray(String src, int length) {
        // 检查参数是否合法
        if (null == src || src.equals("")) {
            return null;
        }
        if (length <= 0) {
            return null;
        }
        // 获取整个字符串可以被切割成字符子串的个数
        int n = (src.length() + length - 1) / length;
        String[] split = new String[n];
        for (int i = 0; i < n; i++) {
            if (i < (n - 1)) {
                split[i] = src.substring(i * length, (i + 1) * length);
            } else {
                split[i] = src.substring(i * length);
            }
        }
        return split;
    }
}
